package org.example.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
//import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.example.common.base.Result;
import org.example.common.exception.BusinessException;
import org.example.constangt.SysLogType;
import org.example.dto.SysDto;
import org.example.dto.SystemDTO;
import org.example.log.Log;
import org.example.service.SysService;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

//@AllArgsConstructor
@Api(tags = "gitegg-system")
//@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RequestMapping("/sys")
@RestController
@RefreshScope
public class SysController {
    @Value("${spring.datasource.maxActive}")
    private String nacosMaxActiveType;
    @Value("${server.port}")
    private Integer serverPort;
    @Resource
    SysService sysService;
    @Autowired
    RedissonClient redisson;
    @Autowired
    RedisTemplate<String,String> template;

//    @ApiOperation(value = "缓存测试设置值")
//    @GetMapping(value = "redis/set")
//    @Log(operModul = "redis/set",description = "method1",methodType = SysLogType.INSERT)
//    public Result redisSet(@RequestParam("id") String id) {
//        RMap<String, String> m = redisson.getMap("test", StringCodec.INSTANCE);
//        m.put("1", id);
//        return Result.success("设置成功");
//    }
//
//    @ApiOperation(value = "缓存测试获取值")
//    @GetMapping(value = "redis/get")
//    public Result redisGet() {
//        BoundHashOperations<String, String, String> hash = template.boundHashOps("test");
//        String t = hash.get("1");
//        return Result.success(t);
//    }



    @GetMapping("/queryList")
    @ApiOperation("列表查询")
    public List<SysDto> queryList() throws InterruptedException, ExecutionException {
        return sysService.queryList();
    }

    @GetMapping("/queryList1")
    @ApiOperation("列表查询")
    public List<SysDto> queryList1()   {
        return sysService.queryList1();
    }

    @PostMapping("/addUserList")
    @ResponseBody
    @ApiOperation("新增user")
    public void addUserList(SysDto sysDto) {
        sysService.addUserList(sysDto);
    }

//
//    @GetMapping(value = "exception")
//    @ApiOperation(value = "自定义异常及返回测试接口")
//    public Result<String> exception() {
//        return Result.dataD(sysService.exception());
//    }
//
//    @PostMapping(value = "valid")
//    @ApiOperation(value = "参数校验测试接口")
//    public Result<SystemDTO> valid(@Valid @RequestBody SystemDTO systemDTO) {
//        return Result.dataD(systemDTO);
//    }
//
//    @PostMapping(value = "nacos")
//    @ApiOperation(value = "Nacos读取配置文件测试接口")
//    public Result<String> nacos() {
//        return Result.dataD(nacosMaxActiveType);
//    }
//
//    @GetMapping("/api/by/id")
//    @ApiOperation(value = "Fegin Get调用测试接口")
//    public Result<Object> feginById(@RequestParam("id") String id) {
//        return Result.dataD(sysService.queryList());
//    }
//
//    @PostMapping("/api/by/dto")
//    @ApiOperation(value = "Fegin Post调用测试接口")
//    public Result<Object> feginByDto(@Valid @RequestBody SystemDTO systemDTO) {
//        return Result.dataD(systemDTO);
//    }
//
//    @GetMapping("/api/ribbon")
//    @ApiOperation(value = "Ribbon调用测试接口")
//    public Result<String> testRibbon() {
//        return Result.dataD("现在访问的服务端口是:" + serverPort);
//    }
//
//    @GetMapping("/sentinel/protected")
//    @ApiOperation(value = "限流测试")
//    @SentinelResource("goods")
//    public Result<String> sentinelProtected() {
//        return Result.dataD("现在访问的是限流测试接口");
//    }
//

    /*** @SentinelResource 改善之前hello接口的资源定于和被流控降级的处理方法* value 定于资源* blockHandler 设置流控降级后的方法(默认该方法必须声明在同一类中)。* 如果不想在同一类中，需添加一个参数指定类，比如 blockHandlerClass = User.class。但是blockHandler对应的方法需static修饰。fallback和这个一样* fallback 单接口出现异常，就可以交给fallback指定的方法进行处理。还可以* blockHandler和fallback如果同时指定，blockHandler优先级更高。* @return*/
    @GetMapping("/sentinelApi")
//    @SentinelResource(value = USER_RESOURCE_NAME,
//            blockHandler = "blockHandlerBySentinelApi",
//            blockHandlerClass = String.class,
//            fallback = "fallbackBySentinelApi",
//            exceptionsToIgnore= {ArithmeticException.class})
    public String getUserResourceName(Integer id) {
//        Entry entry = null;
//        try {
//            entry = SphU.entry("getUserResourceName");
//            int i = 1 / id;
//        } catch (Throwable t) {
//            if (!BlockException.isBlockException(t)) {
//                Tracer.trace(t);
//                System.out.println("熔断-------------------------------------------------------");
//                return  "熔断" ;
//            }
//        } finally {
//            if (entry != null) {
//                entry.exit();
//            }
//        }
//        return  "tc" ;
//        initFlowRules();
        initDegradeRule();

        Entry entry = null;
        int i =  0;
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
            try  {
                entry = SphU.entry("HelloWorld");
                 i = 1 / id;
            } catch (BlockException t) {
                if (!BlockException.isBlockException(t)) {
                    Tracer.trace(t);
                    System.out.println("熔断-------------------------------------------------------");
                    return  "熔断" ;
                }
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }
        return  i+"" ;
    }



    @ApiOperation(value = "慢调用比例熔断策略")
    @GetMapping(value = "sentinel/slow/request/ratio")
    public Result<String> sentinelRR() {
        initDegradeRule();

        Entry entry = null;
        try  {
            entry = SphU.entry("HelloWorld");
            double randomNumber;
            randomNumber = Math.random();
            if (randomNumber >= 0 && randomNumber <= 0.80) {
                Thread.sleep(300L);
            } else if (randomNumber >= 0.80 && randomNumber <= 0.80 + 0.10) {
                Thread.sleep(10L);
            }
        }  catch (Throwable t) {
            t.printStackTrace();
            if (!BlockException.isBlockException(t)) {
                Tracer.trace(t);
            }

        }finally {
            if (entry != null) {
                entry.exit();
            }
        }


        return Result.success("慢调用比例熔断策略");
    }

    @ApiOperation(value = "异常比例熔断策略")
    @PostMapping(value = "sentinel/error/ratio")
    public Result sentinelRatio() {
        initDegradeRule1();
        int i = 1/0;
        return Result.success("成功");
    }

    @ApiOperation(value = "异常数熔断策略")
    @PostMapping(value = "sentinel/error/count")
    public Result sentinelCount(int id) {
        initDegradeRule2();
        int i = 1/0;
        return Result.success("正常");
    }


    @ApiOperation(value = "Gateway路由转发测试")
    @GetMapping(value = "gateway/forward")
    public Result gatewayForward() {
        return Result.success("gitegg-service-system测试数据");
    }


//
//    private static void initFlowRules(){
//        List<FlowRule> rules = new ArrayList<>();
//        FlowRule rule = new FlowRule();
//        rule.setResource("HelloWorld");
//        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//        // Set limit QPS to 20.
//        rule.setCount(20);
//        rules.add(rule);
//        FlowRuleManager.loadRules(rules);
//    }

    private static void initDegradeRule() {
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        DegradeRule rule = new DegradeRule("HelloWorld");
        rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
        rule.setCount(0.8); // Threshold is 70% error ratio
        rule.setCount(200)
                .setMinRequestAmount(5) // 1s5次
                .setTimeWindow(60); // 10s
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 异常比例
     */
    private static void initDegradeRule1() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule("HelloWorld");
        rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
        rule.setCount(0.2); // Threshold is 70% error ratio
        rule.setStatIntervalMs(1000)
                .setMinRequestAmount(5) // 1s5次
                .setTimeWindow(180); // 10s
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 异常数
     */
    private static void initDegradeRule2() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule("HelloWorld");
        rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
        rule.setCount(5); // Threshold is 70% error ratio
        rule.setStatIntervalMs(1000); // 1000ms
        rule.setMinRequestAmount(5);// 1s5次
        rule.setTimeWindow(60); // 10s
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }


}
